package foundation.SurModel;

import java.util.List;

import Jama.Matrix;

public class Predictor {

	
	public static void main(String[] args) {
		
			  double[] seta = {3.382243879472401E-4,0.035734364907680144,3.273281566655918E-12,2.19686286966451E-7,0.023771502240893,
					           6.929713050505073E-7,9.998855084753805E-8,6.103652827658212E-7,3.4058689930812692E-12,9.960654554811215E-7,
					           0.03224605081873039,8.304521354881064E-11,5.445612204259639E-13,7.610670286909373E-7,7.336089069563225E-4,
					           3.637089124371158E-13,1.1703722068859546E-10,3.2313820461732E-8,0.032959708372948614,4.416112400655859E-12,
					           2.4065637707795655E-6,0.007172426633365101};

		 

/*	double[] seta = new double[22];
		for (int i = 0; i < 22; i++) {
			seta[i] = //Math.log(0.01);;Math.exp(-0.00000001);
			0.000011;
		}*/

		double[] p = { 1.0155994550064495,1.568280167594149,1.353532804674697,1.5564435585012757,1.0472699530712695,
				       1.7514595088661027,1.2776200059275813,1.7962775036284415,1.1827820363000299,1.989978495313693,
				       1.966507715309464,1.6539745653482734,1.1079389451309631,1.5573690367679065,1.9822775278529488,
				       1.3252900095894602,1.2293626547665206,1.4159488747655546,1.6765151475184146,1.4346716090196825,
				       1.7588332227606212,1.4403523314915654};
		/*
		 * double[] p=new double[22]; for(int i=0;i<22;i++){ p[i]=2d; }
		 */
		// 加载训练数据集
		Matrix[] data = InOut.load("!!SMDFGA", 0, 150,"");
		Matrix X = data[0];
		double[][] XVals = X.getArray();
		Matrix Y = data[1];
		double[][] YVals = Y.getArray();
		// 加载测试数据集
		Matrix[] datastar = InOut.load("!!SMDFGA", 150, 50,"");
		Matrix Xstar = datastar[0];
		Matrix Ystar = datastar[1];
		double[][] XstarVals = Xstar.getArray();
		double[][] YstarVals = Ystar.getArray();

		Matrix covMat = getCovMat(X, seta, p);
		double meanVal = getMeanVal(covMat, Y);
		double variVal = getVariVal(covMat, meanVal, Y);

		/*
		 * int size=XstarVals.length; for(int i=0;i<size;i++){
		 * System.out.println(InOut.toStrCode(XstarVals[i])); }
		 */

		int YStarSize = Ystar.getRowDimension();
		double maxVal = 379.59601d;//112.5530d;
		double minVal =  1.85845;//1.88698;
		
		double maxVal_real = 34.451900482177734;;
		double minVal_real =2.0755999088287354;;
		

		
			for (int i = 0; i < YStarSize; i++) {
			double[] preVals = predict(X, XstarVals[i], Y, covMat, p, seta, meanVal, variVal);
			double y_real = YstarVals[i][0];
			double k_real=maxVal_real-minVal_real;
			y_real = 0.5 * (y_real + 1) * k_real + minVal_real;//1/y_real;
	
			double y_pre = preVals[0];
			double k=maxVal-minVal;
			y_pre =0.5 * (y_pre + 1) * k + minVal; //1/y_pre;
			double fit=preVals[0]-2*Math.sqrt(preVals[1]);
			
			System.out.println("fit="+fit+",y_real=" + y_real + ",y_pre=" + y_pre + ",diverance=" + (y_pre - y_real) + ",variance="
					+ preVals[1]);
		}

/*	int YSize=Y.getRowDimension();
		
		for (int i = 0; i < YSize; i++) {
			double[] preVals = predict(X, XVals[i], Y, covMat, p, seta, meanVal, variVal);
			double y_real = YVals[i][0];
			double k=maxVal-minVal;
			y_real = 0.5 * (y_real + 1) * k + minVal;
			
			double y_pre = preVals[0];

			y_pre = 0.5 * (y_pre + 1) * k + minVal;
			System.out.println("y_real=" + y_real + ",y_pre=" + y_pre + ",diverance=" + (y_pre - y_real) + ",variance="
					+ preVals[1]);
		}*/
		
	}

	public static double getDist(double[] X1, double[] X2, double seta[], double p[]) {
		double rlt = 0d;

		int size1 = X1.length;
		int size2 = X2.length;
		int size3 = seta.length;
		int size4 = p.length;
		if ((size1 != size2) && (size1 != size3) && (size1 != size4)) {
			throw new IllegalArgumentException("array size no equal");
		} else {
			double[] temp = new double[size1];
			for (int i = 0; i < size1; i++) {
				temp[i] = Math.abs(X1[i] - X2[i]);
			}
			for (int j = 0; j < size1; j++) {
				rlt += Math.pow(temp[j], p[j]) * seta[j];
			}
			rlt = Math.exp(rlt * (-1d));
		}

		return rlt;
	}

	public static Matrix getCovMat(Matrix input, double seta[], double p[]) {
		int rowNum = input.getRowDimension();
		Matrix covMatrix = new Matrix(rowNum, rowNum);
		double[][] inputVals = input.getArray();
		for (int i = 0; i < rowNum; i++) {
			covMatrix.set(i, i, 1d);
			for (int j = i + 1; j < rowNum; j++) {
				double dist = getDist(inputVals[i], inputVals[j], seta, p);
				covMatrix.set(i, j, dist);
				covMatrix.set(j, i, dist);
			}
		}
		return covMatrix;
	}

	public static double getMeanVal(Matrix covMat, Matrix Y) {
		double meanVal = 0d;
		int rowNum1 = covMat.getRowDimension();
		int rowNum2 = Y.getRowDimension();
		if (rowNum1 != rowNum2) {
			throw new IllegalArgumentException("协方差矩阵与样本输出矩阵的行数不等");
		} else {
			Matrix I = new Matrix(rowNum1, 1);
			for (int i = 0; i < rowNum1; i++) {
				I.set(i, 0, 1d);
			}
			// meanVal=(covMat.inverse()).times(Y)
			Matrix T = I.transpose().times(covMat.inverse());
			Matrix A = T.times(Y);
			Matrix B = T.times(I);
			double valA = A.get(0, 0);
			double valB = B.get(0, 0);
			meanVal = valA / valB;
		}

		return meanVal;
	}

	public static double getVariVal(Matrix covMat, double meanVal, Matrix Y) {
		double variVal = 0d;
		int rowNum1 = covMat.getRowDimension();
		int rowNum2 = Y.getRowDimension();
		if (rowNum1 != rowNum2) {
			throw new IllegalArgumentException("协方差矩阵与样本输出矩阵的行数不等");
		} else {
			Matrix I = new Matrix(rowNum1, 1);
			for (int i = 0; i < rowNum1; i++) {
				I.set(i, 0, 1d);
			}
			Matrix T = Y.minus(I.times(meanVal));
			Matrix A = T.transpose().times(covMat.inverse()).times(T);
			double valA = A.get(0, 0);
			variVal = valA / rowNum1;
		}

		return variVal;
	}

	public static double negativeLogLikelihood(Matrix covMat, Matrix Y, double meanVal, double variVal) {
		double likeLihood = 0d;

		int rowNum1 = covMat.getRowDimension();
		int rowNum2 = Y.getRowDimension();
		if (rowNum1 != rowNum2) {
			throw new IllegalArgumentException("协方差矩阵与样本输出矩阵的行数不等");
		} else {
			Matrix I = new Matrix(rowNum1, 1);
			for (int i = 0; i < rowNum1; i++) {
				I.set(i, 0, 1d);
			}
			Matrix T = Y.minus(I.times(meanVal));
			Matrix A = T.transpose().times(covMat.inverse()).times(T);
			double aVal = A.get(0, 0);
			double rightHnd = aVal / (2* variVal);
			double detVal = covMat.det();

			double b = rowNum1/2d*Math.log(2 * Math.PI * variVal) +1/2d*Math.log(detVal);

			likeLihood = b + rightHnd;
		}
		return likeLihood;
	}

	public static Matrix getStarcovMat(Matrix X, double[] XStar, double[] p, double[] seta) {
		int XStarDimension = XStar.length;
		int XColNum = X.getColumnDimension();
		if (XStarDimension != XColNum) {
			throw new IllegalArgumentException("样本的维度与预测点的维度不等");
		}
		int XRowNum = X.getRowDimension();
		double[][] starCovVals = new double[XRowNum][1];
		Matrix starCovMat = new Matrix(starCovVals);

		double[][] XVals = X.getArray();

		for (int i = 0; i < XRowNum; i++) {
			double[] XPoint = XVals[i];
			double dist = getDist(XStar, XPoint, seta, p);
			starCovMat.set(i, 0, dist);

		}
		return starCovMat;
	}

	public static double[] predict(Matrix X, double[] XStar, Matrix Y, Matrix covMat, double[] p, double[] seta,
			double meanVal, double variVal) {
		double[] rlt = new double[2];
		int rowNum1 = X.getRowDimension();
		int rowNum2 = Y.getRowDimension();
		if (rowNum1 != rowNum2) {
			throw new IllegalArgumentException("样本的输入输出矩阵的行数不等");
		}
		XStar= InOut.postDblCodePros(XStar);
		Matrix r = getStarcovMat(X, XStar, p, seta);

		Matrix I = new Matrix(rowNum1, 1);
		for (int i = 0; i < rowNum1; i++) {
			I.set(i, 0, 1d);
		}
		Matrix A = Y.minus(I.times(meanVal));
		Matrix E = covMat.inverse();
		Matrix D = r.transpose().times(E);
		Matrix B = I.transpose().times(E).times(r);
		double f = meanVal + D.times(A).get(0, 0);

		rlt[0] = f;

		double val1 = D.times(r).get(0, 0);
		double BVal = B.get(0, 0);
		double val2 = Math.pow(1 - BVal, 2) / BVal;
		double s = variVal * (1 - val1 + val2);
		rlt[1] = s;

		return rlt;
	}

}
